package com.axialproject.health.exchange;

import com.axialproject.health.exchange.democommunity.entity.CommunityRecord;
import com.axialproject.health.exchange.entity.Patient;
import com.axialproject.health.exchange.entity.PatientLink;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.Query;


public class PatientManager {

    private static final Logger log = Logger.getLogger(PatientManager.class.getName());

    // TODO: we need to make sure that username is not chosen
    public static void savePatient (EntityManager em, Patient patient) {
        try {
            em.persist(patient);
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    public static boolean linkPatientIds (EntityManager em, Long id1, Long id2) throws Exception {
        try {
            Query query = em.createQuery(
                "SELECT l FROM com.axialproject.health.exchange.entity.PatientLink l WHERE l.id1 = :id1 AND l.id2 = :id2")
                    .setParameter("id1", id1)
                    .setParameter("id2", id2);
            List <PatientLink> patientLinks1 = (List <PatientLink>) query.getResultList();
            query = em.createQuery(
                "SELECT l FROM com.axialproject.health.exchange.entity.PatientLink l WHERE l.id2 = :id1 AND l.id1 = :id2")
                    .setParameter("id1", id1)
                    .setParameter("id2", id2);
            List <PatientLink> patientLinks2 = (List <PatientLink>) query.getResultList();

            List <PatientLink> patientLinks = new ArrayList <PatientLink> ();
            patientLinks.addAll(patientLinks1);
            patientLinks.addAll(patientLinks2);

            if (patientLinks == null || patientLinks.size() == 0) {
                PatientLink link = new PatientLink (id1, id2);
                em.persist (link);
                return true;
            } else {
                if (patientLinks.size() > 1) {
                    throw new Exception ("We have more than one links that connects id1=" + id1 + " id2=" + id2);
                }
            }
            
            /*
            Patient p1 = em.find(Patient.class, id1);
            Patient p2 = em.find(Patient.class, id2);
            if (p1.getMasterPatientId() != null && p2.getMasterPatientId() != null && p1.getMasterPatientId().equals(p2.getMasterPatientId())) {
                return;
            }

            List <Patient> ps1 = new ArrayList <Patient> ();
            List <Patient> ps2 = new ArrayList <Patient> ();

            Query query = em.createQuery("SELECT p FROM com.axialproject.health.exchange.entity.Patient p WHERE p.masterPatientId = :masterPatientId");
            if (p1.getMasterPatientId() != null) {
                query.setParameter ("masterPatientId", p1.getMasterPatientId());
                ps1 = (List <Patient>) query.getResultList();
            }
            if (p2.getMasterPatientId() != null) {
                query.setParameter ("masterPatientId", p2.getMasterPatientId());
                ps2 = (List <Patient>) query.getResultList();
            }

            for (Patient p : ps1) {
                p.setMasterPatientId(id1);
            }
            for (Patient p : ps2) {
                p.setMasterPatientId(id1);
            }
            */
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
        return false;
    }

    public static Patient getPatientByUsernameAppName (EntityManager em, String username, String appName) {
        Patient patient = null;
        if (username == null || appName == null) {
            return patient;
        }

        try {
            Query query = em.createQuery(
                "SELECT p FROM com.axialproject.health.exchange.entity.Patient p WHERE p.username = :username AND p.appName = :appName")
                    .setParameter("username", username)
                    .setParameter("appName", appName);
            List <Patient> patients = (List <Patient>) query.getResultList();
            if (patients == null || patients.size() == 0) {
                // return null here
            } else {
                if (patients.size() > 1) {
                    log.severe("More than one patient with same username and appName " + username + " " + appName);
                }
                patient = patients.get(0);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
        return patient;
    }

    public static Patient getPatientById (EntityManager em, Long patientId) {
        Patient patient = null;
        if (patientId == null) {
            return patient;
        }

        try {
            patient = em.find (Patient.class, patientId);
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
        return patient;
    }

    public static List <Patient> getLinkedPatients (EntityManager em, Long patientId) {
        List <Patient> patients = null;
        if (patientId == null) {
            return patients;
        }

        try {
            Query query = em.createQuery(
                "SELECT l FROM com.axialproject.health.exchange.entity.PatientLink l WHERE l.id1 = :patientId")
                    .setParameter("patientId", patientId);
            List <PatientLink> patientLinks1 = (List <PatientLink>) query.getResultList();
            query = em.createQuery(
                "SELECT l FROM com.axialproject.health.exchange.entity.PatientLink l WHERE l.id2 = :patientId")
                    .setParameter("patientId", patientId);
            List <PatientLink> patientLinks2 = (List <PatientLink>) query.getResultList();

            List <PatientLink> patientLinks = new ArrayList <PatientLink> ();
            patientLinks.addAll(patientLinks1);
            patientLinks.addAll(patientLinks2);

            HashSet <Long> ids = new HashSet <Long> ();
            for (PatientLink patientLink : patientLinks) {
                ids.add (patientLink.getId1());
                ids.add (patientLink.getId2());
            }

            patients = new ArrayList <Patient> ();
            for (Long id : ids) {
                patients.add (em.find(Patient.class, id));
            }

        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
        return patients;
    }

    public static List <Patient> getPatientsByAppName (EntityManager em, String appName) {
        List <Patient> patients = null;
        if (appName == null) {
            return patients;
        }

        try {
            Query query = em.createQuery(
                "SELECT p FROM com.axialproject.health.exchange.entity.Patient p WHERE p.appName = :appName")
                    .setParameter("appName", appName);
            patients = (List <Patient>) query.getResultList();
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
        return patients;
    }

    public static void removePatient (EntityManager em, Patient patient) {
        em.remove(patient);
    }

    public static void removePatientLink (EntityManager em, Long id1, Long id2) {
        try {
            Query query = em.createQuery(
                "SELECT l FROM com.axialproject.health.exchange.entity.PatientLink l WHERE l.id1 = :id1 AND l.id2 = :id2")
                    .setParameter("id1", id1)
                    .setParameter("id2", id2);
            List <PatientLink> patientLinks1 = (List <PatientLink>) query.getResultList();
            query = em.createQuery(
                "SELECT l FROM com.axialproject.health.exchange.entity.PatientLink l WHERE l.id1 = :id1 AND l.id2 = :id2")
                    .setParameter("id1", id2)
                    .setParameter("id2", id1);
            List <PatientLink> patientLinks2 = (List <PatientLink>) query.getResultList();

            List <PatientLink> patientLinks = new ArrayList <PatientLink> ();
            patientLinks.addAll(patientLinks1);
            patientLinks.addAll(patientLinks2);

            for (PatientLink patientLink : patientLinks) {
                em.remove(patientLink);
            }

        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
        }
    }

    // THis is for demo
    public static List <CommunityRecord> getCommunityRecords (EntityManager em) {
        try {
            Query query = em.createQuery(
                "SELECT r FROM com.axialproject.health.exchange.democommunity.entity.CommunityRecord r ORDER BY r.testDate DESC");
            List <CommunityRecord> records = (List <CommunityRecord>) query.getResultList();
            return records;
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
            return null;
        }
    }

}
